package com.ruoyi.system.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.page.PageDomain;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.enums.ChannelEnum;
import com.ruoyi.common.enums.OrderStatusEnum;
import com.ruoyi.common.enums.OrderTypeEnum;
import com.ruoyi.common.exception.BusiException;
import com.ruoyi.common.utils.BigDecimalUtil;
import com.ruoyi.common.utils.RequestUtil;
import com.ruoyi.common.utils.sign.SignMD5Util;
import com.ruoyi.system.ali.AliPayDto;
import com.ruoyi.system.ali.ChannelUtil;
import com.ruoyi.system.biz.CashBizService;
import com.ruoyi.system.domain.CashHistory;
import com.ruoyi.system.domain.MerchantLog;
import com.ruoyi.system.domain.Order;
import com.ruoyi.system.domain.UserChannel;
import com.ruoyi.system.dto.ApiByPhoneAddDto;
import com.ruoyi.system.dto.ApiNotifyDto;
import com.ruoyi.system.dto.ApiOrderReceiveAddDto;
import com.ruoyi.system.dto.ApiOrderSelectDto;
import com.ruoyi.system.mapper.OrderMapper;
import com.ruoyi.system.service.*;
import com.ruoyi.system.vo.*;
import com.ruoyi.system.websocket.WebSocketServer1;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;


@Service

public class OrderServiceImpl extends BaseServiceImpl<OrderMapper, Order> implements OrderService {
    public static final Logger log = LoggerFactory.getLogger(DynamicDataSourceContextHolder.class);

    @Resource
    private CashBizService cashService;

    @Resource
    private CashHistoryService cashHistoryService;
    @Resource
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;
    @Resource
    private ISysUserService userService;
    @Resource
    private ISysConfigService configService;
    @Resource
    private UserChannelService userChannelService;
    @Resource
    private MerchantLogService merchantLogService;
    @Resource
    private RedissonClient redissonClient;

    private static String[] surnames = {"赵", "钱", "孙", "李", "周", "吴", "郑", "王", "冯", "陈", "褚", "卫", "蒋", "沈", "韩", "杨", "朱", "秦", "尤", "许",
            "何", "吕", "施", "张", "孔", "曹", "严", "华", "金", "魏", "陶", "姜", "戚", "谢", "邹", "喻", "柏", "水", "窦", "章", "云", "苏", "潘", "葛", "奚", "范", "彭", "郎",
            "鲁", "韦", "昌", "马", "苗", "凤", "花", "方", "俞", "任", "袁", "柳", "酆", "鲍", "史", "唐", "费", "廉", "岑", "薛", "雷", "贺", "倪", "汤", "滕", "殷",
            "罗", "毕", "郝", "邬", "安", "常", "乐", "于", "时", "傅", "皮", "卞", "齐", "康", "伍", "余", "元", "卜", "顾", "孟", "平", "黄", "和",
            "穆", "萧", "尹", "姚", "邵", "湛", "汪", "祁", "毛", "禹", "狄", "米", "贝", "明", "臧", "计", "伏", "成", "戴", "谈", "宋", "茅", "庞", "熊", "纪", "舒",
            "屈", "项", "祝", "董", "梁", "杜", "阮", "蓝", "闵", "席", "季"};
    private static String[] names = {"碧凡", "夏菡", "曼香", "若烟", "半梦", "雅绿", "冰蓝", "灵槐", "平安", "书翠", "翠风", "香巧", "代云", "友巧", "听寒",
            "梦柏", "醉易", "访旋", "亦玉", "凌萱", "访卉", "怀亦", "笑蓝", "春翠", "靖柏", "书雪", "乐枫", "念薇", "靖雁", "寻春", "恨山", "从寒", "忆香",
            "觅波", "静曼", "凡旋", "新波", "代真", "新蕾", "雁玉", "冷卉", "紫山", "千琴", "恨天", "傲芙", "盼山", "怀蝶", "冰兰", "问旋", "从南", "白易",
            "问筠", "如霜", "半芹", "寒雁", "怜云", "寻文", "谷雪", "乐萱", "涵菡", "海莲", "傲蕾", "青槐", "冬儿", "易梦", "惜雪", "宛海", "之柔", "夏青"};

    @Autowired
    private RedisCache redisCache;

    @Resource
    private WebSocketServer1 webSocketServer;

    @Override
    public BigDecimal getFreeze(Long userId) {
        //计算冻结金额
        Order order = new Order();
        order.setUserId(userId);
        order.setFreezeStatus(1);
        BigDecimal sum = this.sum("payAmount", order, null, null);
        return sum;
    }

    @Override
    public CashCountVo countByUserId(Long userId) {
        Order order = new Order();

        order.setUserId(userId);
        Date start = DateUtil.beginOfDay(new Date());
        Date end = new Date();


        //今日金额
        BigDecimal amount = this.sum("amount", order, start, end);
//今日订单数
        int total = this.countByDomain(order, start, end);
        order.setStatus("finish");
        //今日收益
        CashHistory domain = new CashHistory();
        domain.setUserId(userId);
        domain.setSource("user");
        domain.setChangeType("add");
        domain.setType("earning");
        domain.setRemark("订单收益");
        BigDecimal todayEarning = cashHistoryService.sum("changeMoney", domain, start, new Date());
        //BigDecimal todayEarning = this.sum("earning", order, start, end);
        //完成订单数
        int success = this.countByDomain(order, start, end);
        //完成金额
        BigDecimal finishAmount = this.sum("amount", order, start, end);
        //超时
        order.setStatus("timeout");
        int error = this.countByDomain(order, start, end);
        CashCountVo cashCountVo = new CashCountVo();
        cashCountVo.setTodayEarning(todayEarning);
        cashCountVo.setOrderTotal(total);
        cashCountVo.setOrderSuccess(success);
        cashCountVo.setOrderError(error);
        cashCountVo.setAmount(amount);
        cashCountVo.setFinishAmount(finishAmount);
        if (total > 0) {

            double div = NumberUtil.div(success, total);
            String s = NumberUtil.formatPercent(div, 2);
            cashCountVo.setRate(s);
        }
//        Cash cash = cashService.getByUserId(userId);
        BigDecimal freeze = this.getFreeze(userId);
        cashCountVo.setFreezeEarning(freeze);
        CashHistory cashHistory = new CashHistory();
        cashHistory.setUserId(userId);
        cashHistory.setRemark("下级贡献收益");
        BigDecimal fansEarning = cashHistoryService.sum("changeMoney", cashHistory, start, end);
        cashCountVo.setFansEarning(fansEarning);
        return cashCountVo;
    }


    @Override
    public OrderCountVo count(Long userId) {
        SysUser user = userService.check(userId);

        Order domain = new Order();
        domain.setUserId(userId);
        domain.setStatus("paid");
        int paidNum = this.countByDomain(domain);
        Date start = DateUtil.beginOfDay(new Date());
        Date end = new Date();
        OrderCountVo orderCountVo = new OrderCountVo();
        orderCountVo.setPaidNum(paidNum);
        Order order = new Order();
        order.setUserId(userId);
        PageDomain pageDomain = new PageDomain();
        pageDomain.setBeginTime(DateUtil.formatDateTime(DateUtil.beginOfDay(new Date())));
        pageDomain.setEndTime(DateUtil.now());
//        PageResult<Order> page = this.findPage(order, pageDomain);
//        orderCountVo.setTotayNum(page.getTotal() + "");
        //今日总单数
        int totalNum = this.countByDomain(order, start, end);
        //今日总金额
        BigDecimal todayAmount = this.sum("amount", order, start, end);

        order.setOrderStatus(OrderStatusEnum.success.getValue());
        int finishNum = this.countByDomain(order, start, end);

        BigDecimal finishAmount = this.sum("amount", order, start, end);
        orderCountVo.setFinishNum(finishNum);
        String successRate = "0";
        if (totalNum != 0) {
            BigDecimal divide = new BigDecimal(finishNum).divide(new BigDecimal(totalNum), 2, BigDecimal.ROUND_HALF_UP);
            successRate = NumberUtil.formatPercent(divide.doubleValue(), 2);

        }
        orderCountVo.setTotalNum(totalNum);
        orderCountVo.setSuccessRate(successRate);
        orderCountVo.setTotalAmount(todayAmount);
        orderCountVo.setFinishAmount(finishAmount);
        String rate = "0";
        if (todayAmount.compareTo(BigDecimal.ZERO) > 0) {
            BigDecimal divide = finishAmount.divide(todayAmount, 2, BigDecimal.ROUND_HALF_UP);
            rate = NumberUtil.formatPercent(divide.doubleValue(), 2);
            orderCountVo.setRate(rate);
        }
        return orderCountVo;
    }

    private void checkBlackMember(ApiOrderReceiveAddDto apiChinaOrderReceiveAddDto) {
        if (StrUtil.isNotBlank(apiChinaOrderReceiveAddDto.getPayer())) {//黑粉校验
            String blackMembers = configService.selectConfigByKey(apiChinaOrderReceiveAddDto.getMerchantId() + "");
            if (StrUtil.isNotBlank(blackMembers)) {//有黑会员
                String[] split = blackMembers.split(",");
                List<String> list = Arrays.asList(split);
                if (list.contains(apiChinaOrderReceiveAddDto.getPayer())) {
                    throw new BusiException("该会员已被平台拉黑,请联系客服");
                }
            }
        }
    }

    @Override
    @Transactional
    public Object apiOrder(ApiOrderReceiveAddDto apiChinaOrderReceiveAddDto, String source) {
        this.checkBlackMember(apiChinaOrderReceiveAddDto);

        SysUser sysUser = userService.getById(apiChinaOrderReceiveAddDto.getMerchantId());
        if (sysUser == null) {
            throw new BusiException("商户不存在");
        }
        if (StrUtil.equals(sysUser.getRole(), "user")) {
            throw new BusiException("无权限");
        }

        UserChannel userChannel = userChannelService.checkByUserId(sysUser.getUserId(), apiChinaOrderReceiveAddDto.getChannelCode());

        if (!StrUtil.equals("sys", source)) {//下游端需要验签
            SignMD5Util.checkSign(apiChinaOrderReceiveAddDto, sysUser.getSecertKey());
        }
        Order orderPay = new Order();
        BeanUtil.copyProperties(apiChinaOrderReceiveAddDto, orderPay);
        String orderNo = DateUtil.format(new Date(), DatePattern.PURE_DATETIME_PATTERN) + apiChinaOrderReceiveAddDto.getMerchantId() + (int) (Math.random() * 10) + (int) (Math.random() * 10) + (int) (Math.random() * 10) + (int) (Math.random() * 10);
        orderPay.setOrderNo(orderNo);
        orderPay.setMerchantId(apiChinaOrderReceiveAddDto.getMerchantId());
        //获取下单接口返回的url

        //获取支付宝数据
        AliPayDto aliPayDto = new AliPayDto();
        aliPayDto.setAmount(orderPay.getAmount());
        aliPayDto.setOrderNo(orderNo);

        if (StrUtil.isBlank(apiChinaOrderReceiveAddDto.getChannelCode())) {
            apiChinaOrderReceiveAddDto.setChannelCode(ChannelEnum.UID.getCode());
        }

        Object obj = channelUtil.getChannelService(apiChinaOrderReceiveAddDto.getChannelCode()).create(aliPayDto, orderPay);

        //计算手续费
        BigDecimal payRate = userChannel.getReceiveRate();
        BigDecimal payAmount = userChannel.getReceiveAmount();
        BigDecimal multiply = orderPay.getAmount().multiply(payRate);
        BigDecimal serviceFee = multiply.add(payAmount);
        orderPay.setServiceFee(serviceFee);
        orderPay.setRemark("单笔:" + payAmount + ";费率:" + payRate.stripTrailingZeros().toString());
        orderPay.setActualAmount(orderPay.getAmount().subtract(serviceFee));
        orderPay.setOrderStatus(OrderStatusEnum.handling.getValue());
        orderPay.setStatus("paid");
        orderPay.setReturnStatus(0);
        orderPay.setChannelCode(apiChinaOrderReceiveAddDto.getChannelCode());
        orderPay.setChannelName(ChannelEnum.getName(apiChinaOrderReceiveAddDto.getChannelCode()));
//        ApiPayResultVo apiVo = new ApiPayResultVo();
//        apiVo.setAmount(String.valueOf(BigDecimalUtil.setDecimal(orderPay.getAmount())));
//        apiVo.setOrderNo(orderNo);
//        apiVo.setMerchantId(apiChinaOrderReceiveAddDto.getMerchantId());
//        TreeMap<String, String> map = SignMD5Util.objToMap(apiVo);
//        String sign = SignMD5Util.getSign(map, "sign");
//        String payUrl = configService.selectConfigByKey("payUrl");
//        payUrl = payUrl + "?" + SignMD5Util.getStr(map, sign);
//        apiVo.setUrl(payUrl);
//        orderPay.setPic(aliPayVo.getPic());
//        orderPay.setZfbUrl(aliPayVo.getQrCode());
        String serviceNo = "微信" + (RandomUtil.randomInt(3) + 1) + "区/服务器" + (RandomUtil.randomInt(15) + 1);
        String realname = surnames[(int) (Math.random() * surnames.length)] + names[(int) (Math.random() * names.length)];
        orderPay.setGamer(realname);
        orderPay.setServiceNo(serviceNo);
        if (orderPay.getPayAmount() == null) {
            orderPay.setPayAmount(BigDecimalUtil.setDecimal(orderPay.getAmount()));
        }
        this.addDomain(orderPay);
        webSocketServer.SendMessage(orderPay.getOrderNo(), orderPay.getUserId());
        return obj;
    }

    @Override
    @Transactional
    public ApiPayResultVo createOrderByPhone(ApiByPhoneAddDto apiByPhoneAddDto) {
        if (StrUtil.isBlank(apiByPhoneAddDto.getChannelCode())) {
            throw new BusiException("请选择通道编码");
        }
        SysUser sysUser = userService.getById(apiByPhoneAddDto.getMerchantId());
        if (sysUser == null) {
            throw new BusiException("商户不存在");
        }
        if (StrUtil.equals(sysUser.getRole(), "user")) {
            throw new BusiException("无权限");
        }
        UserChannel userChannel = userChannelService.checkByUserId(sysUser.getUserId(), apiByPhoneAddDto.getChannelCode());
        SysUser user = userService.getByUserName(apiByPhoneAddDto.getPhone());
        Order orderPay = new Order();
        BeanUtil.copyProperties(apiByPhoneAddDto, orderPay);
        String orderNo = DateUtil.format(new Date(), DatePattern.PURE_DATETIME_PATTERN) + apiByPhoneAddDto.getMerchantId() + (int) (Math.random() * 10) + (int) (Math.random() * 10) + (int) (Math.random() * 10) + (int) (Math.random() * 10);
        orderPay.setOrderNo(orderNo);
        orderPay.setUserId(user.getUserId());
        orderPay.setUsername(user.getUserName());
        orderPay.setMerchantId(apiByPhoneAddDto.getMerchantId());
        //获取下单接口返回的url

        //获取支付宝数据
        AliPayDto aliPayDto = new AliPayDto();
        aliPayDto.setAmount(orderPay.getAmount());
        aliPayDto.setOrderNo(orderNo);
        // aliPayDto.setNotifyUtl(configService.selectConfigByKey("zfbNotifyUtl") + "/api/order/notify");


        Object obj = channelUtil.getChannelService(apiByPhoneAddDto.getChannelCode()).createByPhone(apiByPhoneAddDto, orderPay);
        //计算手续费
        BigDecimal payRate = userChannel.getReceiveRate();
        BigDecimal payAmount = userChannel.getReceiveAmount();
        BigDecimal multiply = orderPay.getAmount().multiply(payRate);
        BigDecimal serviceFee = multiply.add(payAmount);
        orderPay.setServiceFee(serviceFee);
        orderPay.setRemark("单笔:" + payAmount + ";费率:" + payRate.stripTrailingZeros().toString());
        orderPay.setActualAmount(orderPay.getAmount().subtract(serviceFee));
        orderPay.setOrderStatus(OrderStatusEnum.handling.getValue());
        orderPay.setStatus("paid");
        orderPay.setReturnStatus(0);
        String serviceNo = "微信" + (RandomUtil.randomInt(3) + 1) + "区/服务器" + (RandomUtil.randomInt(15) + 1);
        String realname = surnames[(int) (Math.random() * surnames.length)] + names[(int) (Math.random() * names.length)];
        orderPay.setGamer(realname);
        orderPay.setServiceNo(serviceNo);
        if (orderPay.getPayAmount() == null) {
            orderPay.setPayAmount(BigDecimalUtil.setDecimal(orderPay.getAmount()));
        }
        this.addDomain(orderPay);
        webSocketServer.SendMessage(orderPay.getOrderNo(), orderPay.getUserId());
        return (ApiPayResultVo) obj;
    }


    @Resource
    private ChannelUtil channelUtil;


    private void checkOrderStatus(Order order, String status) {
        if (!StrUtil.equals(order.getStatus(), status)) {
            throw new BusiException("订单状态有误,请刷新后重试");
        }
    }

    @Override
    //确认收款
    @Transactional
    public boolean finish(Long userId, Long id) {
        Order order = this.checkOrder(userId, id);
        if (!StrUtil.equals(order.getStatus(), "paid")) {
            throw new BusiException("状态有误,请刷新后重试");
        }
        finish(id);
        return true;
    }

    @Override
    //超时补单 订单号
    @Transactional
    public boolean reduce(Long userId, Long id) {
        Order order = this.check(id);
        if (!StrUtil.equals(order.getStatus(), OrderStatusEnum.timeOut.getValue())) {
            throw new BusiException("该订单已处理完成");
        }
        if (!StrUtil.equals(order.getOrderStatus(), OrderStatusEnum.handling.getValue())) {
            throw new BusiException("该订单已处理完成");
        }
        Order domain = new Order();
        domain.setId(id);
        domain.setStatus("finish");
        domain.setOrderStatus(OrderStatusEnum.success.getValue());

        order.setStatus("finish");
        order.setOrderStatus(OrderStatusEnum.success.getValue());
        if (order.getFreezeStatus() == 0) {//如果已经释放过
            //扣除收款用户的金额
            CashHistory userCashHis = new CashHistory(userId, order.getPayAmount(), "reduce", "超时补单", "timeout");
            userCashHis.setOrderNo(order.getOrderNo());
            //扣除用户余额
            cashService.updateCash(userId, userCashHis);

        }
        //标记为已释放
        domain.setFreezeStatus(0);
        domain.setSendTime(new Date());
        this.updateOrder(domain);
        //开始分佣
        cashService.benefit(order.getUserId(), order.getOrderNo(), order.getPayAmount(), null, order.getChannelCode());
        //回调下游
        this.notifyAgent(order);

        threadPoolTaskExecutor.execute(() -> {
            try {
                Thread.sleep(2000L);
            } catch (Exception e) {

            }
            checkHIs(order);
        });
        return true;
    }

    @Override
    @Transactional
    public boolean finish(Long id) {
        Order order = this.check(id);
        if (StrUtil.equals(order.getOrderStatus(), OrderStatusEnum.success.getValue())) {
            throw new BusiException("该订单已处理完成");
        }
        if (StrUtil.equals(order.getOrderStatus(), OrderStatusEnum.reject.getValue())) {
            throw new BusiException("该订单已驳回");
        }

        Order domain = new Order();
        domain.setId(id);
        domain.setStatus("finish");
        domain.setOrderStatus(OrderStatusEnum.success.getValue());
        domain.setFreezeStatus(0);

        order.setStatus("finish");
        order.setOrderStatus(OrderStatusEnum.success.getValue());
        order.setFreezeStatus(0);
        //开始分佣
        cashService.benefit(order.getUserId(), order.getOrderNo(), order.getPayAmount(), null, order.getChannelCode());
        domain.setSendTime(new Date());
        this.updateOrder(domain);

        this.notifyAgent(order);

        threadPoolTaskExecutor.execute(() -> {
            try {
                Thread.sleep(2000L);
            } catch (Exception e) {

            }
            checkHIs(order);
        });
        return true;
    }

    //检查是否释放过  释放过则扣除
    private void checkHIs(Order order) {
        CashHistory cashHistory = new CashHistory();
        cashHistory.setOrderNo(order.getOrderNo());
        cashHistory.setRemark("释放冻结资金");
        CashHistory domain1 = cashHistoryService.getDomain(cashHistory);
        if (domain1 != null) {//如果已经释放过 需要在扣除
            //释放金额
            //扣除收款用户的金额
            CashHistory userCashHis = new CashHistory(order.getUserId(), order.getPayAmount(), "reduce", "超时补单", "reduce_");
            userCashHis.setOrderNo(order.getOrderNo());
            //扣除用户余额
            cashService.updateCash(order.getUserId(), userCashHis);
        }
    }

    @Override
    public Order checkOrder(Long userId, Long id) {
        Order order = this.check(id);
        if (!userId.equals(order.getUserId())) {
            throw new BusiException("无权限操作");
        }
        return order;
    }

    @Override
    //订单超时
    @Transactional
    public void timeout(Long id) {
        Order order = this.check(id);
        String status = order.getStatus();
        if (!StrUtil.equals(status, "paid")) {
            throw new BusiException("订单状态有误,请刷新后重试");
        }
        Order domain = new Order();
        domain.setId(id);
        domain.setStatus("timeout");
        this.updateOrder(domain);
    }

    @Override
    public void updateOrder(Order order) {
        RLock lock = redissonClient.getLock("rock_order:" + order.getId()); // 创建分布式锁对象
        try {
            lock.lock(); // 获取锁
            // 执行业务操作...
            this.updateDomain(order);
        } finally {
            lock.unlock(); // 释放锁
        }
    }

    @Override
    public SumAmountVo sumByUserId(Long userId) {
        SumAmountVo sumAmountVo = new SumAmountVo();
        if (userId == null) {
            return sumAmountVo;
        }
        DateTime beginOfDay = DateUtil.beginOfDay(new Date());
        DateTime yestodayBegin = DateUtil.offsetDay(beginOfDay, -1);
        DateTime thisMonth = DateUtil.beginOfMonth(new Date());
        DateTime preMonth = DateUtil.offsetMonth(thisMonth, -1);
        BigDecimal yestoday = baseMapper.sumByUserId(userId, yestodayBegin, beginOfDay);
        BigDecimal today = baseMapper.sumByUserId(userId, beginOfDay, new Date());
        BigDecimal totalAmount = baseMapper.sumByUserId(userId, null, null);
        BigDecimal thisMonthAmount = baseMapper.sumByUserId(userId, thisMonth, new Date());
        BigDecimal preMonthAmount = baseMapper.sumByUserId(userId, preMonth, thisMonth);

        sumAmountVo.setTodayAmount(today);
        sumAmountVo.setYestodayAmount(yestoday);
        sumAmountVo.setTotalAmount(totalAmount);
        sumAmountVo.setPreMonthAmount(preMonthAmount);
        sumAmountVo.setThisMonthAmount(thisMonthAmount);
        return sumAmountVo;
    }

    @Override
    //释放金额
    @Transactional
    public void release(Long id) {
        Order order = this.check(id);
        if (StrUtil.equals(order.getStatus(), "finish")) {
            Order order1 = new Order();
            order1.setFreezeStatus(0);
            order1.setId(order.getId());
            this.updateOrder(order1);
            return;
        }
        Order domain = new Order();
        domain.setId(id);
        domain.setFreezeStatus(0);
        this.updateOrder(domain);
        //检查是否有订单收益
        CashHistory cashHistory = new CashHistory();
        cashHistory.setUserId(order.getUserId());
        cashHistory.setOrderNo(order.getOrderNo());
        cashHistory.setRemark("订单收益");

        PageDomain pageDomain = new PageDomain();
        List<CashHistory> list = cashHistoryService.findList(cashHistory, pageDomain);
        //有订单收益 不释放
        if (CollectionUtil.isNotEmpty(list)) {
            return;
        }
        CashHistory userCashHis = new CashHistory(order.getUserId(), order.getPayAmount(), "add", "释放冻结资金", "thaw");
        userCashHis.setOrderNo(order.getOrderNo());
        cashService.updateCash(order.getUserId(), userCashHis);

    }

    @Override
    //驳回订单  直接将订单完成不回调
    @Transactional
    public void reject(Long id) {
        this.check(id);
        Order domain = new Order();
        domain.setId(id);
        domain.setFreezeStatus(0);
        domain.setOrderStatus(OrderStatusEnum.reject.getValue());
        domain.setStatus("finish");
        this.updateOrder(domain);
    }

    @Override
    public ApiOrderVo selectApiOrder(ApiOrderSelectDto apiOrderSelectDto) {
        Long merchantId = apiOrderSelectDto.getMerchantId();
        SysUser sysUser = userService.check(merchantId);
        Order order = new Order();
        order.setMerchantId(merchantId);
        order.setMerchantOrderNo(apiOrderSelectDto.getMerchantOrderNo());

        order = this.getDomain(order);
        if (order == null) {
            throw new BusiException("订单不存在");
        }
//      UserChannel userChannel = userChannelService.checkByUserId(merchantId, "apiOrderSelectDto.get");
        SignMD5Util.checkSign(apiOrderSelectDto, sysUser.getSecertKey());
        ApiOrderVo apiOrderReceiveVo = BeanUtil.copyProperties(order, ApiOrderVo.class);
        apiOrderReceiveVo.setStatus(order.getOrderStatus());
        return apiOrderReceiveVo;

    }

    @Override
    public Order selectAgentOrder(Long merchantId, String merchantOrderNo) {

        Order order = new Order();
        order.setMerchantId(merchantId);
        order.setMerchantOrderNo(merchantOrderNo);

        order = this.getDomain(order);


        return order;

    }

    //回调下游  加商户余额
    @Transactional
    @Override
    public void notifyAgent(Order orderReceive) {
        if (!StrUtil.equals(OrderStatusEnum.success.getValue(), orderReceive.getOrderStatus())) {
            return;
        }

        try {


            while (!redisCache.getLock("notifyAgent:" + orderReceive.getMerchantId(), "1", 6L)) {//如果不能获取锁  就等着
                log.info("回调商户:{}未获取到锁,时间：{}", orderReceive.getMerchantId(), DateUtil.now());
                Thread.sleep(200L);
            }
            //获取锁后  等待200ms
            Thread.sleep(200L);
            if (StrUtil.equals(OrderStatusEnum.success.getValue(), orderReceive.getOrderStatus())) {
                //已收款
                CashHistory userCashHis = new CashHistory(orderReceive.getMerchantId(), orderReceive.getActualAmount(), "add", orderReceive.getChannelName(), "orderReceive");
                userCashHis.setOrderNo(orderReceive.getOrderNo());
                userCashHis.setMerchantOrderNo(orderReceive.getMerchantOrderNo());
                cashService.updateCash(orderReceive.getMerchantId(), userCashHis);
            }
            redisCache.deleteObject("notifyAgent:" + orderReceive.getMerchantId());
        } catch (Exception e) {
            log.info("回调异常{}", e.getMessage());
        }

        threadPoolTaskExecutor.execute(() -> {

            //回调下游
            SysUser sysUser = userService.check(orderReceive.getMerchantId());
            ApiNotifyDto apiNotifyDto = BeanUtil.copyProperties(orderReceive, ApiNotifyDto.class);
            apiNotifyDto.setMerchantId(orderReceive.getMerchantId());
            apiNotifyDto.setType(OrderTypeEnum.receive.getValue());
            apiNotifyDto.setStatus(orderReceive.getOrderStatus());
            apiNotifyDto.setPic(null);
            String serSign = SignMD5Util.getSerSign(apiNotifyDto, sysUser.getSecertKey());
            apiNotifyDto.setSign(serSign);
            //发送日志
            MerchantLog merchantLog = new MerchantLog();
            merchantLog.setMerchantId(orderReceive.getMerchantId());
            merchantLog.setOperParam(JSONUtil.toJsonStr(apiNotifyDto));

            int i = 0;
            while (i < 5) {
                try {
                    String result = RequestUtil.request(orderReceive.getNotifyUrl(), apiNotifyDto, MediaType.APPLICATION_JSON, HttpMethod.POST, null);

                    // log.info("代收回调下游参数：{},结果:{}", JSONObject.toJSONString(apiNotifyDto), result);
                    if (StrUtil.equals("SUCCESS", result) || StrUtil.equals("success", result)) {
                        merchantLog.setJsonResult(result);
                        merchantLogService.ansyInsert(merchantLog);
                        Order order = new Order();
                        order.setId(orderReceive.getId());
                        order.setReturnStatus(1);

                        this.updateDomain(order);

                        break;
                    }
                    //AsyncFactory
                    Thread.sleep(10000L);
                } catch (InterruptedException e) {
                    //  e.printStackTrace();
                    merchantLog.setJsonResult(e.getMessage());
                    merchantLogService.ansyInsert(merchantLog);
                }
            }

        });
    }

    @Override
    public Order getByOrderNo(String orderNo) {
        Order order = new Order();
        order.setOrderNo(orderNo);
        return this.getDomain(order);

    }


    @Override
    @Async
    public void notice(Order orderReceive) {
        //回调下游
        SysUser check = userService.check(orderReceive.getMerchantId());
        //UserChannel userChannel = userChannelService.checkByUserId(orderReceive.getMerchantId());
        ApiNotifyDto apiNotifyDto = BeanUtil.copyProperties(orderReceive, ApiNotifyDto.class);
        apiNotifyDto.setMerchantId(orderReceive.getMerchantId());
        apiNotifyDto.setType(OrderTypeEnum.receive.getValue());
        apiNotifyDto.setStatus(orderReceive.getOrderStatus());
        apiNotifyDto.setPic(null);
        String serSign = SignMD5Util.getSerSign(apiNotifyDto, check.getSecertKey());
        apiNotifyDto.setSign(serSign);
        if (StrUtil.isBlank(orderReceive.getNotifyUrl())) {
            orderReceive.setReturnStatus(1);
            this.updateDomain(orderReceive);
            return;
        }
        if (!StrUtil.equals(OrderStatusEnum.success.getValue(), orderReceive.getOrderStatus())) {
            log.info("回调下游,订单：{}", JSONObject.toJSONString(orderReceive));
            return;
        }
        String result = RequestUtil.request(orderReceive.getNotifyUrl(), apiNotifyDto, MediaType.APPLICATION_JSON, HttpMethod.POST, null);
        log.info("代收回调下游参数：{},结果:{}", JSONObject.toJSONString(apiNotifyDto), result);
        if (StrUtil.equals("SUCCESS", result) || StrUtil.equals("success", result)) {
            orderReceive.setReturnStatus(1);
            this.updateDomain(orderReceive);
        }


    }


    @Override
    public List<Long> selectUserIds(Date start, Date end) {
        QueryWrapper<Order> queryWrapper = new QueryWrapper<>();
        queryWrapper.ge("create_time", start);
        queryWrapper.lt("create_time", end);
        queryWrapper.select("user_id");
        queryWrapper.groupBy("user_id");
        List<Order> cashHistories = this.baseMapper.selectList(queryWrapper);
        if (CollectionUtil.isEmpty(cashHistories)) {
            return null;
        }

        List<Long> userIds = cashHistories.stream().filter(p -> p != null).map(p -> p.getUserId()).collect(Collectors.toList());
        return userIds;
    }


    @Override
    public List<Long> selectMerchantIds(Date start, Date end) {
        QueryWrapper<Order> queryWrapper = new QueryWrapper<>();
        queryWrapper.ge("create_time", start);
        queryWrapper.lt("create_time", end);
        queryWrapper.select("merchant_id");
        queryWrapper.groupBy("merchant_id");
        List<Order> cashHistories = this.baseMapper.selectList(queryWrapper);
        if (CollectionUtil.isEmpty(cashHistories)) {
            return null;
        }

        List<Long> userIds = cashHistories.stream().filter(p -> p != null).map(p -> p.getMerchantId()).collect(Collectors.toList());
        return userIds;
    }

}
